package com.ruoyi.common.elasticsearch.service.impl;

import com.alibaba.fastjson.JSON;

import com.ruoyi.common.elasticsearch.domain.EsShopDoc;
import com.ruoyi.common.elasticsearch.service.EsShopDocService;
import com.ruoyi.utils.PageResult;
import com.ruoyi.utils.ResponseResult;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author: MrPing
 * @createTime: 2022/4/5 23:27
 * @description:
 */
@Service
public class EsShopDocServiceImpl implements EsShopDocService {


    @Autowired
    private RestHighLevelClient client;
    /*
     * 搜索引擎索引
     */
    public static final String ES_MAPPING = "yuanju_shop_v1";
    /*
     * 搜索引擎分页，每页条数
     */
    public static final Integer ES_PAGENUM = 20;


    @Override
    public Boolean saveShopDoc(EsShopDoc esShopDoc) throws IOException {
        try {
            // 准备 Request对象
            IndexRequest request = new IndexRequest(ES_MAPPING).id(esShopDoc.getId().toString());
            // 准备 json 文档
            request.source(JSON.toJSONString(esShopDoc), XContentType.JSON);


            client.index(request, RequestOptions.DEFAULT);

            return true;
        }catch (Exception e){
            return false;
        }
    }

    @Override
    public Boolean updateShopDoc(EsShopDoc esShopDoc) {
        try {
//            // 1、准备 Request 对象
//            UpdateRequest request = new UpdateRequest(ES_MAPPING, esShopDoc.getId());
//            // 2、准备请求参数
//            request.doc(esShopDoc);
//            // 3、发送请求
//            client.update(request, RequestOptions.DEFAULT);
            // 1、根据id 删除原来的数据
            DeleteRequest request = new DeleteRequest(ES_MAPPING, esShopDoc.getId());
            client.delete(request, RequestOptions.DEFAULT);
            // 2、插入数据
            saveShopDoc(esShopDoc);
            return true;
        }catch (Exception e){
            return false;
        }
    }

    @Override
    public PageResult search(EsShopDoc esShopDoc) {
        try{
            // 1、准备 request
            SearchRequest request = new SearchRequest(ES_MAPPING);
            // 2、准备 DSL
            // 2.1、设置 query 条件
            buildBasicQuery(esShopDoc, request);

            // 2.2、 分页
            int page = esShopDoc.getPage();
            int size = esShopDoc.getSize();
            request.source().from((page - 1) * size).size(size);

            // 2.3、排序
            String location = esShopDoc.getLocation();
            if(location != null && !location.equals("")){
                request.source().sort(SortBuilders.geoDistanceSort("location", new GeoPoint(location))
                        .order(SortOrder.ASC)
                        .unit(DistanceUnit.KILOMETERS)
                );
            }

            // 3、发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            // 4、解析响应
            return handleResponse(response);

        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    /**
     * es 搜索条件
     * @param param
     * @param request
     */
    public void buildBasicQuery(EsShopDoc param, SearchRequest request){
        // 1、构建BooleanQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        String key = param.getKey();
        // 2、关键字搜素
        if(key == null || "".equals(key)){
            boolQuery.must(QueryBuilders.matchAllQuery());
        } else {
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        }
        if(StringUtils.isNotBlank(param.getProvince())){
            if(StringUtils.isBlank(param.getCity()) || "全部".equals(param.getCity())){
                if(StringUtils.isBlank(param.getArea()) || "全部".equals(param.getArea())){
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getProvince() + ""));

                }else{
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getProvince() + ""));
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getCity() + ""));
                }
            }else{
                if(StringUtils.isBlank(param.getArea()) || "全部".equals(param.getArea())){
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getProvince() + ""));
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getCity() + ""));

                }else{
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getProvince() + ""));
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getCity() + ""));
                    boolQuery.filter(QueryBuilders.termQuery("district", param.getArea()));
                }
            }
        }
        if(param.getHomeTypeID() != null){
            boolQuery.must(QueryBuilders.termQuery("tags", param.getHomeTypeID()));
        }

        // 3、距离范围搜素
        String location  = param.getLocation();
        if(StringUtils.isNotBlank(param.getKilometre())){
            GeoDistanceQueryBuilder distanceQueryBuilder = new GeoDistanceQueryBuilder("location");
            distanceQueryBuilder.point(new GeoPoint(location)).distance(param.getKilometre(), DistanceUnit.KILOMETERS);
            boolQuery.filter(distanceQueryBuilder);
        }



        request.source().query(boolQuery);
    }

    /**
     * 解析es搜索到的数据
     * @param response
     * @return
     */
    public PageResult handleResponse(SearchResponse response){
        // 4、解析响应
        SearchHits searchHits = response.getHits();
        // 4.1、获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到：" + total + "条数据");
        // 4.2、文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3、遍历
        ArrayList<EsShopDoc> hotels = new ArrayList<>();
        for (SearchHit hit : hits){
            // 获取文档source
            String json = hit.getSourceAsString();
            // 反序列化
            EsShopDoc esShopDoc = JSON.parseObject(json, EsShopDoc.class);
            // 获取排序值
            Object[] sortValues = hit.getSortValues();
            if(sortValues.length > 0){
                Object sortValue = sortValues[0];
                esShopDoc.setDistance(sortValue);
            }

            hotels.add(esShopDoc);
        }
        return new PageResult(total, hotels);
    }

}
